package com.zhijian.medical.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import com.zhijian.medical.dao.local.ExamPaperMapper;
import com.zhijian.medical.entity.dto.ExamCreateAnswerJsonDto;
import com.zhijian.medical.entity.po.ExamPaper;
import com.zhijian.medical.entity.po.ExamPaperPersonResult;
import com.zhijian.medical.entity.po.ExamPaperQuestion;
import com.zhijian.medical.entity.po.ExamQuestion;
import com.zhijian.medical.entity.vo.request.*;
import com.zhijian.medical.entity.vo.response.*;
import com.zhijian.medical.enums.ExamStatusEnum;
import com.zhijian.medical.enums.ResponseCodeEnum;
import com.zhijian.medical.exception.BusinessException;
import com.zhijian.medical.service.*;
import com.zhijian.medical.util.JsonUtil;
import com.zhijian.medical.util.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 考核-试卷模块业务处理层
 *
 * @author HCG
 * @version: 1.0
 * @date 2022-01-18 16:13:08
 */
@Slf4j
@Service
public class ExamPaperServiceImpl implements ExamPaperService {

    @Autowired
    private ExamPaperMapper mapper;

    @Autowired
    private ExamQuestionService examQuestionService;

    @Autowired
    private ExamAnswerService examAnswerService;

    @Autowired
    private ExamPaperQuestionService examPaperQuestionService;

    @Autowired
    private ExamPaperPersonResultService examPaperPersonResultService;

    @Autowired
    private ExamWarehouseStudyService examWarehouseStudyService;

    /**
     * 默认题目数量
     */
    @Value("${exam.questionNum}")
    private Integer questionNum;

    private static List<String> options = null;

    static {
        //最大6个选项
        options = Arrays.asList("a", "b", "c", "d", "e", "f");
    }

    @Override
    public ExamPaper selectById(Long id) {
        return mapper.selectByPrimaryKey(id);
    }

    @Override
    public ExamPaperVo selectVoById(Long id) {
        return mapper.selectVoById(id);
    }

    @Override
    public void deleteById(Long id) {
        mapper.deleteByPrimaryKey(id);
    }

    @Override
    public Long insert(ExamPaper examPaper) {
        Date now = new Date();
        examPaper.setCreateTime(now);
        examPaper.setUpdateTime(now);
        return mapper.insert(examPaper) > 0 ? examPaper.getId() : 0L;
    }

    @Override
    public boolean update(ExamPaper examPaper) {
        Date now = new Date();
        examPaper.setUpdateTime(now);
        return mapper.updateByPrimaryKey(examPaper) != 0;
    }

    @Override
    public boolean updateByPrimaryKeySelective(ExamPaper record) {
        return mapper.updateByPrimaryKeySelective(record) != 0;
    }

    @Override
    public Integer count(ExamPaperSearchVo examPaperSearchVo) {
        return mapper.count(examPaperSearchVo);
    }

    @Override
    public List<ExamPaperVo> selectList(ExamPaperSearchVo examPaperSearchVo) {
        return mapper.selectList(examPaperSearchVo);
    }

    @Override
    public Page<ExamPaperVo> selectPage(ExamPaperSearchVo examPaperSearchVo) {
        //先直接查总数
        int count = count(examPaperSearchVo);
        //分页
        Page<ExamPaperVo> page = new Page<>(true, count, examPaperSearchVo.getPageNum(), examPaperSearchVo.getPageSize());
        examPaperSearchVo.setStartIndex(page.getStartIndex());
        page.setPage(true);
        page.setTotalCount(count);
        List<ExamPaperVo> responseVos = this.selectList(examPaperSearchVo);
        page.setData(responseVos);
        return page;
    }

    @Override
    public Long generate(ExamStartVo examStartVo) {
        ExamPaper examPaper = ExamPaper.builder()
                .warehouseId(examStartVo.getWarehouseId())
                .questionNum(questionNum)
                .studyId(examStartVo.getStudyId())
                .build();

        //此题库下面的问题数目
        Integer questionCount = examQuestionService.count(ExamQuestionSearchVo.builder()
                .warehouseId(examPaper.getWarehouseId())
                .build());
        if (questionCount < questionNum) {
            throw new BusinessException(ResponseCodeEnum.FAILURE.code, "此题库问题数量不足");
        }

        Date now = new Date();

        Set<String> randomEleSet = RandomUtil.randomEleSet(CollUtil.newArrayList("a", "b", "c", "d", "e", "f", "g", "h", "I", "J", "K", "L", "M", "N", "O", "P", "Q",
                "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"), 6);
        //六位随机数，随机数规则：字母支持大小写与数字结合
        String code = String.format("%s%s", DateUtil.format(now, new SimpleDateFormat("yyyyMMddHHmmss")),
                Arrays.toString(randomEleSet.toArray()).replace(",", "").replace("[", "").replace("]", "").replace(" ", "").trim());

        //问题id集合
        String ids = examQuestionService.selectIds(examPaper.getWarehouseId());
        //随机挑符合预期目标的题目id出来
        Set<String> questionIdsSet = RandomUtil.randomEleSet(CollUtil.newArrayList(ids.split(",")), questionNum);
        examPaper.setCode(code);
        examPaper.setQuestionIds(Arrays.toString(questionIdsSet.toArray()).replace(" ", "").replace("[", "").replace("]", "").trim());
        examPaper.setUserId(examStartVo.getUserId());
        examPaper.setStatus(ExamStatusEnum.UN_SUBMIT.getCode().byteValue());
        //保存试卷，得到试卷id
        Long examPaperId = this.insert(examPaper);

        questionIdsSet.forEach(questionId -> {
            //找出这个题目的所有答案
            List<ExamAnswerVo> examAnswerVos = examAnswerService.selectList(ExamAnswerSearchVo.builder()
                    .questionId(Long.valueOf(questionId))
                    .build());
            if (!CollectionUtils.isEmpty(examAnswerVos)) {
                if (examAnswerVos.size() > 1) {
                    //说明是选择题，要随机排答案
                    List<ExamCreateAnswerJsonDto> examCreateAnswerJsonDtoList = new ArrayList<>();
                    //不确定有几个选项，所以取答案与自定义选项的最小值
                    int maxSize = options.size() > examAnswerVos.size() ? examAnswerVos.size() : options.size();
                    for (int i = 0; i < maxSize; i++) {
                        ExamAnswerVo examAnswerVo;
                        //随机数，在上述最小值内随机取答案
                        int randomInt;
                        do {
                            randomInt = RandomUtil.randomInt(maxSize);
                            examAnswerVo = examAnswerVos.get(randomInt);
                        } while (Objects.isNull(examAnswerVo));
                        //取得一个后，把list中的这个坐标元素置为null，以免下次再取到
                        examAnswerVos.set(randomInt, null);
                        examCreateAnswerJsonDtoList.add(ExamCreateAnswerJsonDto.builder()
                                .option(options.get(i))
                                .answerId(examAnswerVo.getId())
                                .answerContent(examAnswerVo.getContent())
                                .build());
                    }
                    examPaperQuestionService.insert(ExamPaperQuestion.builder()
                            .examPaperId(examPaperId)
                            .questionId(Long.valueOf(questionId))
                            .provideAnswers(JSONUtil.toJsonStr(examCreateAnswerJsonDtoList))
                            .build());
                }
            }

        });
        return examPaperId;
    }

    @Transactional(rollbackFor = Exception.class, value = "localTransactionManager")
    @Override
    public ExamDoingVo start(ExamStartVo examStartVo) {

        //先看这个人有没有这个学习模块的试卷
        ExamPaper examPaper = this.selectByUserIdAndStudyId(examStartVo.getUserId(), examStartVo.getStudyId());

        Long examPaperId;
        if (Objects.isNull(examPaper)) {
            //如果没有，要先生成
            examPaperId = generate(examStartVo);
            if (Objects.isNull(examPaperId)) {
                throw new BusinessException(ResponseCodeEnum.FAILURE.code, "生成试卷失败");
            }
        } else {
            //有的话，直接拿现成的
            examPaperId = examPaper.getId();
        }

        return detail(examStartVo.getStudyId(), examStartVo.getUserId(), examPaperId);
    }

    @Override
    public ExamDoingVo detail(Long studyId, Long userId, Long examPaperId) {
        //试卷
        ExamPaper examPaper = selectById(examPaperId);
        if (Objects.isNull(examPaper)) {
            throw new BusinessException(ResponseCodeEnum.FAILURE.code, "此次考核不存在或者已被删除");
        }

        List<ExamDoingVo.ContentVo> contentVoList = new ArrayList<>();
        //找出这张试卷的生成题目
        List<ExamPaperQuestionVo> examPaperQuestionVos = examPaperQuestionService.selectList(ExamPaperQuestionSearchVo.builder()
                .examPaperId(examPaperId)
                .build());

        if (CollectionUtils.isEmpty(examPaperQuestionVos)) {
            throw new BusinessException(ResponseCodeEnum.FAILURE.code, "此次考核试题异常");
        }
        //找试卷-人员结果表，以此确定此人有没有提交过考试
        Integer count = examPaperPersonResultService.count(ExamPaperPersonResultSearchVo.builder()
                .examPaperId(examPaperId)
                .userId(userId)
                .build());
        //是否已经考试
        boolean isStart = count > 0;
        examPaperQuestionVos.forEach(examPaperQuestionVo -> {
            //根据题目id找到题目内容
            ExamQuestion examQuestion = examQuestionService.selectById(examPaperQuestionVo.getQuestionId());
            //组装回显vo类
            ExamDoingVo.ContentVo contentVo = ExamDoingVo.ContentVo.builder()
                    .answers(JsonUtil.toArray(examPaperQuestionVo.getProvideAnswers(), ExamCreateAnswerJsonDto.class))
                    .questionId(examPaperQuestionVo.getQuestionId())
                    .questionContent(examQuestion.getContent())
                    .build();
            if (isStart) {
                //如果已经考试，还要把这个人对这个题目的提交选项查找出来，进行页面的回显
                List<ExamPaperPersonResultVo> examPaperPersonResultVos = examPaperPersonResultService.selectList(ExamPaperPersonResultSearchVo.builder()
                        .examPaperQuestionId(examPaperQuestionVo.getId())
                        .examPaperId(examPaperId)
                        .build());
                if (!CollectionUtils.isEmpty(examPaperPersonResultVos)) {
                    contentVo.setSelectAnswer(examPaperPersonResultVos.get(0).getSelectAnswer());
                }
            }
            contentVoList.add(contentVo);
        });

        return ExamDoingVo.builder()
                .id(examPaperId)
                .code(examPaper.getCode())
                .content(contentVoList)
                .status(examPaper.getStatus())
                .studyId(studyId)
                .build();
    }

    @Transactional(rollbackFor = Exception.class, value = "localTransactionManager")
    @Override
    public ExamResultVo submit(ExamSubmitVo examSubmitVo) {
        //试卷id
        Long examPaperId = examSubmitVo.getId();
        //试卷
        ExamPaper examPaper = selectById(examPaperId);
        if (Objects.isNull(examPaper)) {
            throw new BusinessException(ResponseCodeEnum.FAILURE.code, "此次考核不存在或者已被删除");
        }
        //学习-题库关系表
        ExamWarehouseStudyVo examWarehouseStudyVo = examWarehouseStudyService.selectVoByStudyId(examSubmitVo.getStudyId());
        if (Objects.isNull(examWarehouseStudyVo)) {
            throw new BusinessException(ResponseCodeEnum.FAILURE.code, "此学习模块还未关联题库");
        }
        //先直接删除之前的记录，重新保存
        examPaperPersonResultService.deleteByExamPaperId(examPaperId);

        examSubmitVo.getSelectContent().forEach(contentVo -> {
            List<ExamPaperQuestionVo> examPaperQuestionVos = examPaperQuestionService.selectList(ExamPaperQuestionSearchVo.builder()
                    .examPaperId(examPaperId)
                    .questionId(contentVo.getQuestionId())
                    .build());
            if (!CollectionUtils.isEmpty(examPaperQuestionVos)) {
                //保存提交的选项
                examPaperPersonResultService.insert(ExamPaperPersonResult.builder()
                        .examPaperQuestionId(examPaperQuestionVos.get(0).getId())
                        .selectAnswer(contentVo.getSelectAnswer())
                        .examPaperId(examPaperId)
                        .questionId(contentVo.getQuestionId())
                        .userId(examSubmitVo.getUserId())
                        .build());
            }
        });

        //直接查出做对了多少道题目
        Integer rightCount = examPaperPersonResultService.selectRightCountByExamPaperIdAndUserId(examPaperId, examSubmitVo.getUserId());
        //分数
        Integer score = rightCount * 2;
        //结果
        String result = rightCount >= examWarehouseStudyVo.getAcceptanceLine() ? "合格" : "不合格";
        this.updateByPrimaryKeySelective(ExamPaper.builder()
                .id(examPaperId)
                .score(score)
                .result(result)
                //状态改为已提交
                .status(ExamStatusEnum.ALREADY_SUBMIT.getCode().byteValue())
                .submitTime(new Date())
                .build());
        return ExamResultVo.builder()
                .score(score)
                .result(result)
                .id(examPaperId)
                .code(examPaper.getCode())
                .build();
    }

    @Override
    public ExamPaper selectByUserIdAndStudyId(Long userId, Long studyId) {
        return mapper.selectByUserIdAndStudyId(userId, studyId);
    }

}